import java.util.Random;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class DataGen {
	public static void main( String[] args ) {
		final char[] chs = {'a','b','c','d','e','f','g','h','i','j',
			'k','l','m','n','o','p','q','r','s','t','u','v','w','x',
			'y','z','A','B','C','D','E','F','G','H','I','J','K','L',
			'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
			'!','@','#','$','%','^','&','*','_','-','+','=',':',';',
			',','.','?','/','~','`'};

		final int LINE_COUNT = (200 * 10000)+1;
		final int THREAD_COUNT = 3;
		final int PART_LINE_COUNT = LINE_COUNT/THREAD_COUNT;
		final int STRING_LEN=70;
		final String fileName = "data";
		final int QUEUE_LEN = 10000;

		ArrayBlockingQueue<String> q = new ArrayBlockingQueue<>(QUEUE_LEN);

		ExecutorService pool =
			Executors.newFixedThreadPool( THREAD_COUNT+1);

		try {
			for (int i=0; i<THREAD_COUNT; ++i) 
				pool.submit( new Gen(PART_LINE_COUNT,STRING_LEN, chs, q) );

			pool.submit( new Wt(q, fileName) );

			pool.shutdown();

		} catch ( Exception e ) { e.printStackTrace(); }

	}
}

class Gen implements Runnable {
	private int LINE_COUNT;
	private BlockingQueue<String> queue;
	private int STRING_LEN;
	private char[] chs;

	public Gen(int count, int string_length, char[] chs,
			BlockingQueue<String> queue)
	{
		LINE_COUNT=count;
		STRING_LEN=string_length;
		this.queue=queue;
		this.chs=chs;
	}

	@Override
	public void run() {
		Random random = new Random();
		StringBuilder sb = new StringBuilder();

		try {
			for (int i=0; i<LINE_COUNT; ++i) {
				for (int j=0; j<STRING_LEN; ++j)
					sb.append( chs[ random.nextInt( chs.length ) ] );

				queue.put( sb.toString() );
				sb.delete(0, sb.length()-1);	// clear sb
			}
		} catch( Exception e ) { e.printStackTrace();  }
	}
}

class Wt implements Runnable {
	private ArrayBlockingQueue<String> queue;
	private PrintWriter w;

	public Wt(ArrayBlockingQueue<String>queue, String outputFile) {
		this.queue=queue;
		try {
			w = new PrintWriter(outputFile);
		} catch( Exception e ) { e.printStackTrace();  }
	}

	@Override
	public void run() {
		String ele;
		try {
			while (true) {
				ele = queue.poll(200, TimeUnit.MILLISECONDS);
				if ( ele == null ) break;
				w.println( ele );
			}

			w.close();
		} catch( Exception e ) { e.printStackTrace();  }
	}
}
